package io.zrpc.extension;

import io.zrpc.core.common.Ordered;
import io.zrpc.core.common.utils.ClassUtils;
import io.zrpc.core.exception.ZRpcRuntimeException;

import java.util.Arrays;

/**
 * 扩展接口包装类
 */
public class ExtensionClass<T> implements Ordered {

    /**
     * 扩展接口实现类名
     */
    private final Class<? extends T> clazz;
    /**
     * 扩展接口自定义名称
     */
    private final String alias;
    /**
     * 扩展编码，必须唯一
     */
    private byte code;
    /**
     * 是否单例
     */
    private boolean singleton;

    /**
     * 扩展点优先级，小的优先级高
     */
    private int order;

    /**
     * 是否覆盖其它高{@link #order}的同名扩展
     */
    protected boolean override;

    /**
     * 排斥其它扩展，可以排斥掉其它高{@link #order}的扩展
     */
    protected String[] rejection;

    /**
     * 扩展接口实例对象, 仅单例时存在
     */
    private volatile transient T instance;

    public ExtensionClass(Class<? extends T> clazz, String alias) {
        this.clazz = clazz;
        this.alias = alias;
    }

    /**
     * 得到扩展接口的实例对象, 单例则返回{@link #instance}, 多例则返回新创建对象
     */
    public T getExtInstance(){
        return getExtInstance(null, null);
    }

    /**
     * 得到扩展接口的实例对象, 单例则返回{@link #instance}, 多例则返回新创建对象
     *
     * @param argsType 构造函数参数类型
     * @param args     构造函数参数值
     * @return 扩展点对象实例 ext instance
     */
    public T getExtInstance(Class<?>[] argsType,Object[] args){
        if (clazz !=null){
            try{
                if (singleton){
                    if (instance==null){
                        synchronized (this){
                            if (instance == null){
                                instance = ClassUtils.newInstanceWithArgs(clazz, argsType, args);
                            }
                        }
                    }
                    return instance;
                }else {
                    return ClassUtils.newInstanceWithArgs(clazz, argsType, args);
                }
            }catch (ZRpcRuntimeException e){
                throw e;
            }catch (Exception e){
                throw new ZRpcRuntimeException("", e);
            }
        }
        throw new ZRpcRuntimeException("");
    }

    public Class<? extends T> getClazz() {
        return clazz;
    }

    public String getAlias() {
        return alias;
    }

    public byte getCode() {
        return code;
    }

    public ExtensionClass<T> setCode(byte code) {
        this.code = code;
        return this;
    }

    public boolean isSingleton() {
        return singleton;
    }

    public ExtensionClass<T> setSingleton(boolean singleton) {
        this.singleton = singleton;
        return this;
    }

    @Override
    public int getOrder() {
        return order;
    }

    public ExtensionClass<T> setOrder(int order) {
        this.order = order;
        return this;
    }

    public boolean isOverride() {
        return override;
    }

    public ExtensionClass<T> setOverride(boolean override) {
        this.override = override;
        return this;
    }

    public String[] getRejection() {
        return rejection;
    }

    public ExtensionClass<T> setRejection(String[] rejection) {
        this.rejection = rejection;
        return this;
    }

    @Override
    public String toString() {
        return "ExtensionClass{" +
                "clazz=" + clazz +
                ", alias='" + alias + '\'' +
                ", code=" + code +
                ", singleton=" + singleton +
                ", order=" + order +
                ", override=" + override +
                ", rejection=" + Arrays.toString(rejection) +
                ", instance=" + instance +
                '}';
    }
}
